extern crate rand;
extern crate termion;

mod lib;

use lib::*;
use std::env;

use std::io::{Write, stdout, stdin};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use std::thread::sleep;

use termion::async_stdin;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;

fn main() {

    let arguments = std::env::args();
    if arguments.len() > 1 {
        test();
    }
    else {
        init();
        game_loop();
    }

}

fn init() {
    println!("\n ～＊～＊～ ＴＥＴＡＮＵＳ ～＊～＊～ \n");
}
    

fn game_loop() {
    let blocks:Vec<Grid> = prep_tets();
    let mut bag = generate_bag();
    let mut board = main_grid();
    let mut level = 1;
    let mut score = 0;
    let min_step = Duration::from_millis(100);
    
    
    // static step duration between inputs
    // mutable drop duration between drops
	// time to next duration

    let mut tet:Grid = blocks[bag.remove(0)].clone();
    let mut current_pos:(usize, usize) = place_new_tet(&board, &tet);

	let mut stdin = async_stdin().keys();
	let mut stdout = stdout().into_raw_mode().unwrap();
	
	let mut start = SystemTime::now();
	let mut droptime = 53;
	let mut steps = 0;
	
    loop {
		let input = stdin.next();
		if let Some(Ok(key)) = input {
			match key {
                // exit game
                termion::event::Key::Esc => break,

                // rotate left
                termion::event::Key::Char('z') |termion::event::Key::Char('h') => {
                    let new_ro = rotate_left(&tet);
                    if eval_over(&new_ro, &board, current_pos.0, current_pos.1) {
                        tet = new_ro;
                        print_board(&overlay_grid(&tet, board.clone(), current_pos));
                    }

                    },
                // rotate right
                termion::event::Key::Char('x') |termion::event::Key::Char('l') => {
                    let new_ro = rotate_right(&tet);
                    if eval_over(&new_ro, &board, current_pos.0, current_pos.1) {
                        tet = new_ro;
                        print_board(&overlay_grid(&tet, board.clone(), current_pos));
                    }


                    },

                // shift left
                termion::event::Key::Left | termion::event::Key::Char('a') => {

                    let new_pos = move_tet(&tet, &board, (0, -1), current_pos);
                    if new_pos != current_pos {
                        print_board(&overlay_grid(&tet, board.clone(), new_pos));
                        current_pos = new_pos;
                    }

                    },

                // soft drop
                termion::event::Key::Down | termion::event::Key::Char('s') => {
                    let new_pos = move_tet(&tet, &board, (-1, 0), current_pos);
                    if new_pos != current_pos {
                        print_board(&overlay_grid(&tet, board.clone(), new_pos));
                        current_pos = new_pos;
                    }


                    },

                // shift right
                termion::event::Key::Right|  termion::event::Key::Char('d') => {
                    
                    let new_pos = move_tet(&tet, &board, (0, 1), current_pos);
                    if new_pos != current_pos {
                        print_board(&overlay_grid(&tet, board.clone(), new_pos));
                        current_pos = new_pos;
                    }


                    },
                _ => {},
            }
        }
		if steps >= droptime {
            let new_pos = move_tet(&tet, &board, (-1, 0), current_pos);
            if new_pos != current_pos {
                //board = overlay_grid(&tet, board, new_pos);
                print_board(&overlay_grid(&tet, board.clone(), new_pos));
                current_pos = new_pos;
            }
            else {
                board = overlay_grid(&tet, board, current_pos);
                let filled:Vec<usize> = find_filled(&board);
                if filled.len() > 0 {
                    for i in 0 .. filled.len(){
                        board.remove(filled[i]);
                        let x = board[0].clone();
                        board.push(x);
                    }
                }
                tet = blocks[bag.remove(0)].clone();
                if bag.len() < 2 {
                    let mut refill = generate_bag();
                    bag.append(&mut refill);
                }
                current_pos = place_new_tet(&board, &tet)
            }

            steps = 0;
		}

    // The entire draw method should be able to work from a reference
    // to save memory
		sleep(Duration::from_micros(16742));
		steps += 1;

    }

}

fn test() {
    println!("Generating bag");

    let mut sack:Vec<usize> = generate_bag();

    println!("Building tetraminos");
    let mut tets:Vec<Grid> = Vec::new();
    for i in sack.iter() {
        tets.push(build_tet(*i));

    }

    let mut board = main_grid();
	let a:usize = 4;
	let b:usize = 4;
    let c:usize = 2;
    let d:usize = 2;
    if eval_over (&tets[0], &board, a, b) {
		board = overlay_grid(&tets[0].clone(), board, (a, b));
	}
	if eval_over (&tets[1], &board, c, d) {
	    board = overlay_grid(&tets[1].clone(), board, (c, d));
	}
    // Need separate printer for the board
    print_board(&board);

}

fn print_board(board:&Grid) {
    println!("");
    let mut lines: Vec<String> = Vec::new();
    for row in 0 .. board.len() {
        lines.push(String::new());
        for i in 3 .. board[row].len()-1 {
            if board[row][i] == 0 {
                lines[row].push_str("XX");
            }
            else {
                lines[row].push_str("██");
            }
        }
    }
	//remove top two lines from screen
    
    while lines.len() > 3 {
        println!("\r{}", lines.pop().unwrap());
    }


}

fn print_tet(tet:Grid) {
    println!("");
    let mut lines: Vec<String> = Vec::new();
    for row in 0 .. tet.len() {
        lines.push(String::new());
        for i in 0 .. tet[row].len() {
            if tet[row][i] == 0 {
                lines[row].push_str("XX");
            }
            else {
                lines[row].push_str("██");
            }
        }
        
    }
    while lines.len() > 0 {
        println!("{}", lines.pop().unwrap());
    }


}
